﻿#region File Description
//  XAEnima 
//  License: GNU/GPL
//  Developer: Federico Leonardo Motta
//  File description: Handler for the LED stimulator.
#endregion

#region Using Statements
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;
using bci2.utils;
#endregion

namespace XAEnima.Core.Stimulation.External
{
    public class LEDDriver
    {
        public int BASE_COMMAND_VALUE;
        public int SET_PERIODS;
        public int LEDS_ON;
        public int LEDS_OFF;

        public SerialPort serial;
        private float[] Frequencies = new float[4];
        public Boolean isOn = false;
        public Boolean isOpen = false;
        
        public LEDDriver()
        {
            BASE_COMMAND_VALUE = Convert.ToInt32("0xAAAAAAAA", 16);// short.Parse("AAAAAAAA", System.Globalization.NumberStyles.HexNumber);
            SET_PERIODS = (int)(BASE_COMMAND_VALUE+1);
            LEDS_ON = (int)(BASE_COMMAND_VALUE+2);
            LEDS_OFF = (int)(BASE_COMMAND_VALUE+3);
        }
        public struct LED_Command
        {
	        public int command;
	        public short[] Data;
        }

        public LED_Command curCommand;

        // inizializzo la porta seriale
        public int init(String port)
        {
            serial = new SerialPort();
            if (String.Compare(port, null) == 0)
            {
                serial.PortName = null;
                return 1;
            }

            serial.BaudRate = 38400;
            //serial.ReadTimeout = 1000;
            //serial.WriteTimeout = 1000;
            serial.Parity = Parity.None;
            //serial.StopBits = StopBits.One;
            //serial.DataBits = 8;

            if (serial.PortName == null)
                serial= new SerialPort();

            serial.PortName = port;

            try
            {
                serial.Open();
            }
            //TODO: Gestire l'eccezione
            catch (Exception e) {
                Console.WriteLine("Si è verificato un errore:");
                Console.WriteLine(e);
                return 1;
            }
            // Stop();
            Thread.Sleep(10);
            if (serial.IsOpen)
            {
                isOpen = true;
                return 0;
            }else
                return 1;
        }

        // settaggio frequenza di stimolazione
        public Boolean setPeriods(short[] periods, short num)
        {
	        // 0 = left
	        // 1 = right
	        // 2 = up
	        // 3 = down
            byte[] stica = new byte[20];

            curCommand = new LED_Command();
            curCommand.Data = new short[4];

	        if (serial == null) 
                return false;

	        int i;

            if (num <= 0 || num > 8) {
                Console.WriteLine("Si è verificato un errore:");
                Console.WriteLine("Il numero di periodi passati alla funzione setPeriods(short[],short) è errato.");
                return false;
            } 
	        for(i=0; i<num;i++)
	        {
		        curCommand.Data[i] = periods[i];
	        }
	        curCommand.command = SET_PERIODS;
            stica = bci2.utils.utils.LEDCommandToByte(curCommand);

            int size = 4 + num * 2;
            try
            {
                serial.Write(stica, 0, size);
                serial.Read(stica, 0, 0);
            }catch(InvalidOperationException){
                try { serial.Open(); }
                catch(UnauthorizedAccessException e){
                    Console.WriteLine("Si è verificato un errore:");
                    Console.WriteLine(e);
                    return false;
                }
                if (serial.IsOpen) { isOpen = true; }
                serial.Write(stica, 0, size);
                serial.Read(stica, 0, 0);
            }
	        //cout<<stica<<endl;
	        if (isOn==true)
		        start();
	        return true;
        }

        // partono i led

        public int start()
        {
            byte[] stica = new byte[20];
            if (serial == null)
                return 0;

	        isOn=true;
            curCommand = new LED_Command();
            curCommand.Data = new short[4];
	
	        curCommand.command = LEDS_ON;


            stica = bci2.utils.utils.LEDCommandToByte(curCommand);

            serial.Write(stica, 0, 12);

            serial.Read(stica, 0, 0);
	        return 1;
        }

        // ferma i led
        public int stop()
        {
            byte[] stica = new byte[20];
            if (serial == null)
                return 0;

            isOn = false;
            curCommand = new LED_Command();
            curCommand.Data = new short[4];

            curCommand.command = LEDS_OFF;


            stica = bci2.utils.utils.LEDCommandToByte(curCommand);

            serial.Write(stica, 0, 12);

            serial.Read(stica, 0, 0);
            return 1;
        }

        // chiusura comunicazione
        public void close()
        {
            serial.Close();
        }

        public void SetFrequencies(int left, int right, int up, int down)
        {
            //5,9 = 43 //6,9 = 37 //8 = 32 //9,14 = 28
            //9,8 = 26 //11,13 = 23 //12,19 = 21 //12,8 = 20
            //14,22 = 18 //15,05 = 17 //16 = 16 //17 = 15
            Frequencies[0] = left;
            Frequencies[1] = right;
            Frequencies[2] = up;
            Frequencies[3] = down;
                short[] freq = new short[4];
                for (int i = 0; i < 4; i++)
                    freq[i] = (short)Frequencies[i];
                    setPeriods(freq, 4);

        }

        public Boolean IsOpen {
            get { return isOpen; }
        }

        public Boolean IsOn
        {
            get { return isOn; }
        }

    }
}
